﻿
Imports osi.root.template
Imports osi.root.lock
Imports osi.root.procedure
Imports osi.root.formation
Imports osi.root.utils

Public Class singleton_alloc(Of T, PARA_T)
    Inherits __do(Of allocator(Of T, PARA_T), PARA_T, singleton(Of T, PARA_T))

    Public Overrides Function at(ByRef i As allocator(Of T, PARA_T),
                                 ByRef j As PARA_T) As singleton(Of T, PARA_T)
        Return make_singleton(i, j)
    End Function
End Class

Public Class singleton_invoke(Of T, PARA_T)
    Inherits __do(Of singleton(Of T, PARA_T), pointer(Of T), event_comb)

    Public Overrides Function at(ByRef i As singleton(Of T, PARA_T),
                                 ByRef j As pointer(Of T)) As event_comb
        assert(Not i Is Nothing)
        Return i(j)
    End Function
End Class

Public Module _singleton
    Public Function make_singleton(Of T, PARA_T)(ByVal alloc As allocator(Of T, PARA_T),
                                                 ByVal parameter As PARA_T) As singleton(Of T, PARA_T)
        Return New singleton(Of T, PARA_T)(alloc, parameter)
    End Function
End Module

Public Class singleton(Of T, PARA_T)
    Private ReadOnly alloc As allocator(Of T, PARA_T)
    Private ReadOnly parameter As PARA_T
    Private ReadOnly instance As pointer(Of T)
    Private ReadOnly begin As wrapper(Of singleentry)
    Private ReadOnly finish As wrapper(Of singleentry)

    Public Sub New(ByVal alloc As allocator(Of T, PARA_T),
                   ByVal parameter As PARA_T)
        assert(Not alloc Is Nothing)
        Me.alloc = alloc
        Me.parameter = parameter
        Me.instance = New pointer(Of T)()
        Me.begin = New wrapper(Of singleentry)()
        Me.finish = New wrapper(Of singleentry)()
    End Sub

    Default Public ReadOnly Property allocate(ByVal i As pointer(Of T)) As event_comb
        Get
            Dim ec As event_comb = Nothing
            Return New event_comb(Function() As Boolean
                                      If finish.in_use() Then
                                          Return eva(i, +instance) AndAlso
                                                 goto_end()
                                      ElseIf begin.mark_in_use() Then
                                          ec = alloc(instance, parameter)
                                          Return waitfor(ec) AndAlso
                                                 goto_next()
                                      Else
                                          Return waitfor(finish) AndAlso
                                                 goto_next()
                                      End If
                                  End Function,
                                  Function() As Boolean
                                      If Not ec Is Nothing Then
                                          If ec.end_result() Then
                                              assert(finish.mark_in_use())
                                          Else
                                              Return False
                                          End If
                                      End If
                                      Return eva(i, +instance) AndAlso
                                             goto_end()
                                  End Function)
        End Get
    End Property
End Class
